#include "../inc/hart_master.h"
#include "../inc/hart_master_rsp.h"

static hart_master_init_t *handle;
BOOL(*hart_command_rsp_ptr_arr[HART_COMMAND_MAX])
(const hart_command_rsp_t *const data, hart_response_t *resp);

// 统计在线设备数量
static uint16_t hart_master_online_device_count(void)
{
    uint16_t count = 0;
    for (uint8_t i = 0; i < HART_IO_MAXIMUM_NUMBER_CARDS; i++)
    {
        io_system_card_t *card = &hart_master_attribute.io_system.cards[i];
        for (uint8_t j = 0; j < HART_IO_MAXIMUM_NUMBER_CHANNELS_CARD; j++)
        {
            io_system_channel_t *channel = &card->channels[j];
            for (uint8_t k = 0; k < HART_IO_MAXIMUM_NUMBER_DEVICES_CHANNEL; k++)
            {
                io_system_device_t *device = &channel->devices[k];
                if (device->online)
                    count++;
            }
        }
    }
    return count;
}

// 获取设备
static io_system_device_t *hart_master_get_device(uint8_t card_index, uint8_t channel_index, uint8_t device_index)
{
    if (card_index >= HART_IO_MAXIMUM_NUMBER_CARDS)
        return NULL;
    if (channel_index >= HART_IO_MAXIMUM_NUMBER_CHANNELS_CARD)
        return NULL;
    if (device_index >= HART_IO_MAXIMUM_NUMBER_DEVICES_CHANNEL)
        return NULL;
    io_system_card_t *card = &hart_master_attribute.io_system.cards[card_index];
    io_system_channel_t *channel = &card->channels[channel_index];
    io_system_device_t *device = &channel->devices[device_index];
    return device;
}

// 获取通道消息计数
static io_system_message_count_t *hart_master_get_channel_message_count(uint8_t card_index, uint8_t channel_index)
{
    if (card_index >= HART_IO_MAXIMUM_NUMBER_CARDS)
        return NULL;
    if (channel_index >= HART_IO_MAXIMUM_NUMBER_CHANNELS_CARD)
        return NULL;
    io_system_card_t *card = &hart_master_attribute.io_system.cards[card_index];
    io_system_channel_t *channel = &card->channels[channel_index];
    return &channel->message_count;
}

// 获取设备通过索引
static io_system_device_info_t *hart_master_get_device_by_identifier(uint16_t identifier)
{
    io_system_device_info_t *device_info = osel_mem_alloc(sizeof(io_system_device_info_t));
    for (uint8_t i = 0; i < HART_IO_MAXIMUM_NUMBER_CARDS; i++)
    {
        io_system_card_t *card = &hart_master_attribute.io_system.cards[i];
        for (uint8_t j = 0; j < HART_IO_MAXIMUM_NUMBER_CHANNELS_CARD; j++)
        {
            io_system_channel_t *channel = &card->channels[j];
            for (uint8_t k = 0; k < HART_IO_MAXIMUM_NUMBER_DEVICES_CHANNEL; k++)
            {
                io_system_device_t *device = &channel->devices[k];
                if (device->identifier == identifier)
                {
                    device_info->card_index = i;
                    device_info->channel_index = j;
                    device_info->device = device;
                    return device_info;
                }
            }
        }
    }
    return NULL;
}

static BOOL hart_master_command_undef_rsp(const hart_command_rsp_t *const data, hart_response_t *resp)
{
    return FALSE;
}

/**
 * @brief 读取I/O系统功能
 * @param {hart_command_rsp_t} *data
 * @param {hart_response_t} *resp
 * @return {*}
 */
BOOL hart_master_command_74_rsp(const hart_command_rsp_t *const data, hart_response_t *resp)
{
    if (data->delimiter.bits.frame_type == HART_STX_FRAME) // 请求帧, 主->从
    {
        if (FALSE == is_broadcast_address((uint8_t *)data->address, data->address_length))
        {
            return FALSE;
        }

        *resp->data_p++ = HART_IO_MAXIMUM_NUMBER_CARDS;         // I/O卡的最大数量
        *resp->data_p++ = HART_IO_MAXIMUM_NUMBER_CHANNELS_CARD; // 每个I/O卡的最大通道数
        // 每个通道的最大子设备数
        *resp->data_p++ = HART_IO_MAXIMUM_NUMBER_DEVICES_CHANNEL; // 每个通道最大设备数
        // 检测到的设备数量（计数包括I/O系统本身）
        uint16_t count = hart_master_online_device_count();
        *resp->data_p++ = HI_UINT16(count + 1);
        *resp->data_p++ = LO_UINT16(count + 1);
        // I/O系统支持的最大延迟响应数
        *resp->data_p++ = HART_IO_MAXIMUM_NUMBER_DELAY_RESPONSE;
        // 信道通信的主模式。0=二级主机；1=主控形状（默认）
        if (count == 0)
        {
            *resp->data_p++ = 250; // 如果I/0系统没有到子设备的物理HART通信通道，则主模式必须返回250“未使用
        }
        else
        {
            *resp->data_p++ = handle->address_bit;
        }

        // 向子设备发送命令时要使用的重试计数。有效范围为2到5。默认情况下重试3次。
        *resp->data_p++ = HART_IO_MAXIMUM_NUMBER_RETRY_COUNT;
    }
    else
    {
    }
    return TRUE;
}

/**
 * @brief 轮询子设备
 * @param {hart_command_rsp_t} *data
 * @param {hart_response_t} *resp
 * @return {*}
 */
BOOL hart_master_command_75_rsp(const hart_command_rsp_t *const data, hart_response_t *resp)
{
    if (data->delimiter.bits.frame_type == HART_STX_FRAME) // 请求帧, 主->从
    {
        if (data->data_length < sizeof(hart_command_75_t))
        {
            resp->code = RESPONSE_COMMUNICATION_CODE_5;
            return TRUE;
        }
        if (FALSE == is_broadcast_address((uint8_t *)data->address, data->address_length))
        {
            return FALSE;
        }

        uint8_t card_index, channel_index, device_index;
        io_system_device_t *device;
        card_index = data->data.command_75.card;
        channel_index = data->data.command_75.channel;
        device_index = data->data.command_75.poll_address;

        if (card_index >= HART_IO_MAXIMUM_NUMBER_CARDS)
        {
            resp->code = RESPONSE_COMMUNICATION_CODE_21;
            return TRUE;
        }

        if (channel_index >= HART_IO_MAXIMUM_NUMBER_CHANNELS_CARD)
        {
            resp->code = RESPONSE_COMMUNICATION_CODE_22;
            return TRUE;
        }

        device = hart_master_get_device(card_index, channel_index, device_index);
        if (device == NULL)
        {
            resp->code = RESPONSE_COMMUNICATION_CODE_9;
            return TRUE;
        }

        if (device->online == FALSE)
        {
            resp->code = RESPONSE_COMMUNICATION_CODE_9;
            return TRUE;
        }

        *resp->data_p++ = 254;                                     // 默认254
        *resp->data_p++ = HI_UINT16(device->extended_device_type); // 扩展设备类型
        *resp->data_p++ = LO_UINT16(device->extended_device_type);
        *resp->data_p++ = device->m2s_preambles_limit_count;        // 主设备到从设备的最少同步前导码数量
        *resp->data_p++ = device->hart_revision;                    // 本设备实施的HART协议主要版本号。对于HART版本7。该值必须是数字7
        *resp->data_p++ = device->device_revision;                  // 设备版本
        *resp->data_p++ = device->device_software_revision;         // 设备软件版本，254,255保留
        *resp->data_p++ = device->device_hardware_revision.version; // （高5bits）硬件版本号，31保留;（低3bits）5.10 物理信号
        resp->data_p++;                                             // 保留
        osel_memcpy(resp->data_p, device->device_id, 3);            // 设备ID，长ID的后3个字节
        resp->data_p += 3;
        if (device->hart_revision == HART_PROTOCOL_VERSION_7)
        {
            *resp->data_p++ = device->s2m_preambles;                         // 从设备到主设备的响应前导码个数
            *resp->data_p++ = device->last_device_variable;                  // 上一个设备变量，这表示应用程序应在现场设备中找到的最后一个设备变量代码（在执行Command 54时读取设备的变量）
            *resp->data_p++ = HI_UINT16(device->configuration_update_count); // 配置被更新的次数
            *resp->data_p++ = LO_UINT16(device->configuration_update_count);
            *resp->data_p++ = device->extended_device_status;                      // 扩展现场设备状态未指定的任何位都是未定义的，必须设置为零。
            *resp->data_p++ = HI_UINT16(device->manufacturer_identification_code); // 制造商标识码
            *resp->data_p++ = LO_UINT16(device->manufacturer_identification_code);
            *resp->data_p++ = HI_UINT16(device->private_label_distributor_code); // 私有标签分销商代码
            *resp->data_p++ = LO_UINT16(device->private_label_distributor_code);
            *resp->data_p++ = device->device_profile; // 设备配置文件
        }
    }
    else
    {
    }
    return TRUE;
}

/**
 * @brief 读取子设备标识摘要
 * @param {hart_command_rsp_t} *data
 * @param {hart_response_t} *resp
 * @return {*}
 */
BOOL hart_master_command_84_rsp(const hart_command_rsp_t *const data, hart_response_t *resp)
{
    uint16_t identifier;
    if (data->delimiter.bits.frame_type == HART_STX_FRAME) // 请求帧, 主->从
    {
        if (data->data_length < sizeof(hart_command_84_t))
        {
            resp->code = RESPONSE_COMMUNICATION_CODE_5;
            return TRUE;
        }
        if (FALSE == is_broadcast_address((uint8_t *)data->address, data->address_length))
        {
            return FALSE;
        }

        io_system_device_info_t *info;
        identifier = B2S_UINT16(data->data.command_84.identifier);
        info = hart_master_get_device_by_identifier(identifier);
        if (info == NULL)
        {
            resp->code = RESPONSE_COMMUNICATION_CODE_9;
            return TRUE;
        }
        // 回复数据
        *resp->data_p++ = HI_UINT16(info->device->identifier);
        *resp->data_p++ = LO_UINT16(info->device->identifier);
        *resp->data_p++ = info->card_index;
        *resp->data_p++ = info->channel_index;
        *resp->data_p++ = HI_UINT16(info->device->manufacturer_identification_code);
        *resp->data_p++ = LO_UINT16(info->device->manufacturer_identification_code);
        *resp->data_p++ = HI_UINT16(info->device->extended_device_type);
        *resp->data_p++ = LO_UINT16(info->device->extended_device_type);
        osel_memcpy(resp->data_p, info->device->device_id, 3);
        resp->data_p += 3;
        *resp->data_p++ = 0; // 保留
        osel_memcpy(resp->data_p, info->device->long_tag, HART_PACKED32_LEN);
        resp->data_p += HART_PACKED32_LEN;
        *resp->data_p++ = info->device->device_revision;
        *resp->data_p++ = info->device->device_profile;
        *resp->data_p++ = HI_UINT16(info->device->private_label_distributor_code);
        *resp->data_p++ = LO_UINT16(info->device->private_label_distributor_code);
        osel_mem_free(info);
    }
    else
    {
    }
    return TRUE;
}

/**
 * @brief 读取I/O通道统计信息
 * @param {hart_command_rsp_t} *data
 * @param {hart_response_t} *resp
 * @return {*}
 */
BOOL hart_master_command_85_rsp(const hart_command_rsp_t *const data, hart_response_t *resp)
{
    if (data->delimiter.bits.frame_type == HART_STX_FRAME) // 请求帧, 主->从
    {
        io_system_message_count_t *message_count;
        if (data->data_length < sizeof(hart_command_85_t))
        {
            resp->code = RESPONSE_COMMUNICATION_CODE_5;
            return TRUE;
        }
        if (FALSE == is_broadcast_address((uint8_t *)data->address, data->address_length))
        {
            return FALSE;
        }
        if (data->data.command_85.card >= HART_IO_MAXIMUM_NUMBER_CARDS)
        {
            resp->code = RESPONSE_COMMUNICATION_CODE_21;
            return TRUE;
        }

        if (data->data.command_85.channel >= HART_IO_MAXIMUM_NUMBER_CHANNELS_CARD)
        {
            resp->code = RESPONSE_COMMUNICATION_CODE_22;
            return TRUE;
        }
        message_count = hart_master_get_channel_message_count(data->data.command_85.card, data->data.command_85.channel);
        if (message_count == NULL)
        {
            resp->code = RESPONSE_COMMUNICATION_CODE_2;
            return TRUE;
        }

        *resp->data_p++ = data->data.command_85.card;
        *resp->data_p++ = data->data.command_85.channel;
        *resp->data_p++ = HI_UINT16(message_count->stx);
        *resp->data_p++ = LO_UINT16(message_count->stx);
        *resp->data_p++ = HI_UINT16(message_count->ack);
        *resp->data_p++ = LO_UINT16(message_count->ack);
        *resp->data_p++ = HI_UINT16(message_count->ostx);
        *resp->data_p++ = LO_UINT16(message_count->ostx);
        *resp->data_p++ = HI_UINT16(message_count->oack);
        *resp->data_p++ = LO_UINT16(message_count->oack);
        *resp->data_p++ = HI_UINT16(message_count->back);
        *resp->data_p++ = LO_UINT16(message_count->back);
    }
    else
    {
    }
    return TRUE;
}

/**
 * @brief 读取子设备统计信息
 * @param {hart_command_rsp_t} *data
 * @param {hart_response_t} *resp
 * @return {*}
 */
BOOL hart_master_command_86_rsp(const hart_command_rsp_t *const data, hart_response_t *resp)
{
    if (data->delimiter.bits.frame_type == HART_STX_FRAME) // 请求帧, 主->从
    {
        uint16_t identifier;
        if (data->data_length < sizeof(hart_command_86_t))
        {
            resp->code = RESPONSE_COMMUNICATION_CODE_5;
            return TRUE;
        }
        if (FALSE == is_broadcast_address((uint8_t *)data->address, data->address_length))
        {
            return FALSE;
        }
        io_system_device_info_t *info;
        identifier = B2S_UINT16(data->data.command_86.identifier);
        info = hart_master_get_device_by_identifier(identifier);
        if (info == NULL)
        {
            resp->code = RESPONSE_COMMUNICATION_CODE_2;
            return TRUE;
        }

        *resp->data_p++ = HI_UINT16(info->device->identifier);
        *resp->data_p++ = LO_UINT16(info->device->identifier);
        *resp->data_p++ = HI_UINT16(info->device->message_count.stx);
        *resp->data_p++ = LO_UINT16(info->device->message_count.stx);
        *resp->data_p++ = HI_UINT16(info->device->message_count.ack);
        *resp->data_p++ = LO_UINT16(info->device->message_count.ack);
        *resp->data_p++ = HI_UINT16(info->device->message_count.back);
        *resp->data_p++ = LO_UINT16(info->device->message_count.back);

        osel_mem_free(info);
    }
    else
    {
    }
    return TRUE;
}

/**
 * @brief 写入I/O系统重试计数
 * @param {hart_command_rsp_t} *data
 * @param {hart_response_t} *resp
 * @return {*}
 */
BOOL hart_master_command_87_rsp(const hart_command_rsp_t *const data, hart_response_t *resp)
{
    if (data->delimiter.bits.frame_type == HART_STX_FRAME) // 请求帧, 主->从
    {
        uint8_t master_mode = 0;
        if (data->data_length < sizeof(hart_command_87_t))
        {
            resp->code = RESPONSE_COMMUNICATION_CODE_5;
            return TRUE;
        }
        if (FALSE == is_broadcast_address((uint8_t *)data->address, data->address_length))
        {
            return FALSE;
        }
        master_mode = data->data.command_87.master_mode;
        if (master_mode != HART_IO_PRIMARY_MODE && master_mode != HART_IO_SECONDARY_MODE)
        {
            resp->code = RESPONSE_COMMUNICATION_CODE_2;
            return TRUE;
        }
        hart_master_attribute.io_system.master_mode = master_mode;

        // 回复数据
        *resp->data_p++ = master_mode;
    }
    else
    {
    }
    return TRUE;
}

/**
 * @brief 写入I/O系统重试计数
 * @param {hart_command_rsp_t} *data
 * @param {hart_response_t} *resp
 * @return {*}
 */
BOOL hart_master_command_88_rsp(const hart_command_rsp_t *const data, hart_response_t *resp)
{
    if (data->delimiter.bits.frame_type == HART_STX_FRAME) // 请求帧, 主->从
    {
        uint8_t retry_count = 0;
        if (data->data_length < sizeof(hart_command_88_t))
        {
            resp->code = RESPONSE_COMMUNICATION_CODE_5;
            return TRUE;
        }
        if (FALSE == is_broadcast_address((uint8_t *)data->address, data->address_length))
        {
            return FALSE;
        }
        retry_count = data->data.command_88.retry_count;
        if (retry_count < 2)
        {
            resp->code = RESPONSE_COMMUNICATION_CODE_4;
            return TRUE;
        }
        if (retry_count > 5)
        {
            resp->code = RESPONSE_COMMUNICATION_CODE_3;
            return TRUE;
        }
        hart_master_attribute.io_system.retry_count = retry_count;

        // 回复数据
        *resp->data_p++ = retry_count;
    }
    else
    {
    }
    return TRUE;
}

BOOL hart_master_rsp_init(const hart_master_init_t *const init)
{
    if (!DBG_ASSERT(init != NULL __DBG_LINE))
        return FALSE;

    handle = (hart_master_init_t *)init;
    for (uint16_t i = 0; i < HART_COMMAND_MAX; i++)
    {
        hart_command_rsp_ptr_arr[i] = hart_master_command_undef_rsp;
    }
    hart_command_rsp_ptr_arr[HART_COMMAND_74] = hart_master_command_74_rsp;
    hart_command_rsp_ptr_arr[HART_COMMAND_75] = hart_master_command_75_rsp;
    hart_command_rsp_ptr_arr[HART_COMMAND_84] = hart_master_command_84_rsp;
    hart_command_rsp_ptr_arr[HART_COMMAND_85] = hart_master_command_85_rsp;
    hart_command_rsp_ptr_arr[HART_COMMAND_86] = hart_master_command_86_rsp;
    hart_command_rsp_ptr_arr[HART_COMMAND_87] = hart_master_command_87_rsp;
    hart_command_rsp_ptr_arr[HART_COMMAND_88] = hart_master_command_88_rsp;
    return TRUE;
}
